//
// Created by Administrator on 2022/10/31.
//

#ifndef ONIX_MEMORY_H
#define ONIX_MEMORY_H

#include <onix/types.h>
#include <onix/onix.h>

// 一页的大小 4K
#define PAGE_SIZE           0x1000
// 可用内存开始的位置
#define MEMORY_BASE         0x100000
// 内核占用内存大小
#define KERNEL_MEMORY_SIZE  0x1000000
// 内核缓存地址
#define KERNEL_BUFFER_MEM   0x800000
// 内核缓存大小
#define KERNEL_BUFFER_SIZE  0x400000
// 内存虚拟磁盘地址
#define KERNEL_RAMDISK_MEM  (KERNEL_BUFFER_MEM + KERNEL_BUFFER_SIZE)
// 内存虚拟磁盘大小
#define KERNEL_RAMDISK_SIZE 0x400000

// 用户程序地址
#define USER_EXEC_ADDR      KERNEL_MEMORY_SIZE
// 用户栈大小
#define USER_STACK_SIZE     0x200000
// 用户栈顶
#define USER_STACK_TOP      0x8000000
// 用户栈底
#define USER_STACK_BOTTOM   (USER_STACK_TOP - USER_STACK_SIZE)

// 内核页目录
#define KERNEL_PAGE_DIR     0x1000
// 内核页表
static u32 KERNEL_PAGE_TABLE[] = {
        0x2000, 0x3000, 0x4000, 0x5000
};

typedef struct page_entry_t
{
    u32 present : 1;  // 在内存中
    u32 write : 1;    // 0 只读 1 可读可写
    u32 user : 1;     // 1 所有人 0 超级用户 DPL < 3
    u32 pwt : 1;      // page write through 1 直写模式，0 回写模式
    u32 pcd : 1;      // page cache disable 禁止该页缓冲
    u32 accessed : 1; // 被访问过，用于统计使用频率
    u32 dirty : 1;    // 脏页，表示该页缓冲被写过
    u32 pat : 1;      // page attribute table 页大小 4K/4M
    u32 global : 1;   // 全局，所有进程都用到了，该页不刷新缓冲
    u32 ignored : 3;  // 该安排的都安排了，送给操作系统吧
    u32 index : 20;   // 页索引
} _packed page_entry_t;

// 读取内存检测的结果数据
void memory_init(u32 magic, u32 addr);
void memory_map_init();
void mapping_init();

u32 get_cr2();

u32 get_cr3();
void set_cr3(u32 pde);

static void enable_page();

// 获取页目录
static page_entry_t *get_pde();
// 获取页表
static page_entry_t *get_pte(u32 vaddr, bool create);
// 刷新快表
static void flush_tlb(u32 vaddr);

// 分配 count 个连续的内核页
u32 alloc_kpage(u32 count);

// 释放 count 个连续的内核页
void free_kpage(u32 vaddr, u32 count);

// 将 vaddr 映射物理内存
void link_page(u32 vaddr);

// 去掉 vaddr 对应的物理内存映射
void unlink_page(u32 vaddr);

void memory_test();

// 拷贝当前页目录
page_entry_t *copy_pde();

// 释放页目录
void free_pde();

// 缺页异常
void page_fault(
        u32 vector,
        u32 edi, u32 esi, u32 ebp, u32 esp,
        u32 ebx, u32 edx, u32 ecx, u32 eax,
        u32 gs, u32 fs, u32 es, u32 ds,
        u32 vector0, u32 error, u32 eip, u32 cs, u32 eflags);

// 系统调用brk
int32 sys_brk(void *addr);

#endif //ONIX_MEMORY_H
